package asia.gkc.test.handler;

import asia.gkc.test.common.Observable;
import asia.gkc.test.common.Observer;
import asia.gkc.test.common.RegisterType;
import asia.gkc.test.protocol.DefaultParser;
import asia.gkc.test.util.DataModel;
import org.reflections.Reflections;

import java.util.*;

/**
 * File Name: HealthData.java
 * Function:
 *
 * @author jakes.
 * @version 1.0
 * @since 6/28/16 5:07 PM
 */

public class HealthData implements Observable {
    private static class HealthDataSingleton {
        private static final HealthData healthData = new HealthData();
    }

    public static final HealthData getInstance() {
        return HealthDataSingleton.healthData;
    }

    private Map<String, List<Observer>> observersMap = new HashMap<String, List<Observer>>();

    public HealthData() {
        Reflections reflections = new Reflections("asia.gkc.test.observer");
        Set<Class<?>> obs = reflections.getTypesAnnotatedWith(RegisterType.class);
        Set<String> typeSet = new HashSet<>();
        for (Class<?> clazz : obs) {
            String[] types = clazz.getAnnotation(RegisterType.class).value();
            try {
                Observer observer = (Observer)clazz.newInstance();
                for (String type : types) {
                    typeSet.add(type);
                    System.out.println("Found observed type: " + type);
                    registerObserver(observer, type);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        DefaultParser.setTypes(typeSet);
    }

    public void registerObserver(Observer observer, String type) {
        List<Observer> observers = observersMap.get(type);

        if (observers == null) {
            observers = new ArrayList<>();
            observersMap.put(type, observers);
        }

        observers.add(observer);
    }

    public void unregisterObserver(Observer observer, String type) {
        List<Observer> observers = observersMap.get(type);

        int i = observers.indexOf(observer);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    public void notifyObservers(DataModel data, String type) {
        List<Observer> observers = observersMap.get(type);

        for (Observer observer : observers) {
            observer.update(this, data);
        }
    }
}
